﻿
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Wise.Util
{
    /// <summary>
    /// 加密工具
    /// 
    /// </summary>
    /// <remarks>
    /// 本例采用 密码块链接模式（CBC）
    /// </remarks>
    /// <see cref="http://blog.csdn.net/ronhu/article/details/46052767"/>
    public class SecurityHelper : HelperBase<SecurityHelper>
    {


        static string DEFAULT_PASSWORD = "2010ee18-24f1-4947-bbc7-cf5c4bf26146";

        static string DEFAULT_VECTOR = "68dba006-db75-4e00-9dd1-1e00a5559acf";



        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="input">输入</param>
        /// <param name="password">密码</param>
        /// <param name="vector">加密向量</param>
        /// <param name="mode">密码模式</param>
        /// <returns></returns>
        public static string Encrypt(string input, string password = null, string vector = null, CipherMode mode = CipherMode.CBC)
        {
            return instance.doEncrypt(input, password, vector, mode);
        }


        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="input">输入</param>
        /// <param name="password">密码</param>
        /// <param name="vector">加密向量</param>
        /// <param name="mode">密码模式</param>
        /// <returns></returns>
        public static byte[] Encrypt(byte[] input, string password = null, string vector = null, CipherMode mode = CipherMode.CBC)
        {
            return instance.doEncrypt(input, password, vector, mode);
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="input">输入</param>
        /// <param name="password">密码</param>
        /// <param name="vector">加密向量</param>
        /// <param name="mode">密码模式</param>
        /// <returns></returns>
        public static string Decrypt(string input, string password = null, string vector = null, CipherMode mode = CipherMode.CBC)
        {
            return instance.doDecrypt(input, password, vector, mode);
        }


        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="input">输入</param>
        /// <param name="password">密码</param>
        /// <param name="vector">加密向量</param>
        /// <param name="mode">密码模式</param>
        /// <returns></returns>
        public static byte[] Decrypt(byte[] input, string password = null, string vector = null, CipherMode mode = CipherMode.CBC)
        {
            return instance.doDecrypt(input, password, vector, mode);
        }


        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="input">输入</param>
        /// <param name="password">密码</param>
        /// <param name="vector">加密向量</param>
        /// <param name="mode">密码模式</param>
        /// <returns></returns>
        protected virtual string doDecrypt(string input, string password, string vector, CipherMode mode)
        {
            if (String.IsNullOrWhiteSpace(input))
            {
                return String.Empty;
            }
            byte[] myInput =Convert.FromBase64String(input);
            byte[] buffer = instance.doDecrypt(myInput, password, vector, mode);
            return Encoding.UTF8.GetString(buffer);
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="input">输入</param>
        /// <param name="password">密码</param>
        /// <param name="vector">加密向量</param>
        /// <param name="mode">密码模式</param>
        /// <returns></returns>
        protected virtual byte[] doDecrypt(byte[] input, string password, string vector, CipherMode mode)
        {
            if (input == null || input.Length == 0)
            {
                return new byte[0];
            }
            if (string.IsNullOrWhiteSpace(password))
            {
                password = DEFAULT_PASSWORD;
            }
            if (string.IsNullOrWhiteSpace(vector))
            {
                vector = DEFAULT_VECTOR;
            }
            //必须转成散列字节数组，否则会抛出 指定键的大小对于此算法无效
            MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
            byte[] key = hashmd5.ComputeHash(Encoding.UTF8.GetBytes(password));
            try
            {
                var des = new TripleDESCryptoServiceProvider
                {
                    Key = key,
                    Mode = mode,
                    Padding = PaddingMode.PKCS7
                };
                if (mode == CipherMode.CBC)
                {
                    //3des 仅支持8字节向量，其他任何长度都不支持！
                    //des 可以支持8字节、16字节
                    des.IV = hashmd5.ComputeHash(Encoding.UTF8.GetBytes(vector)).Take(8).ToArray();
                }
                var desDecrypt = des.CreateDecryptor();
                byte[] buffer = input;
                byte[] result = desDecrypt.TransformFinalBlock(buffer, 0, buffer.Length);
                return result;
            }
            catch (Exception exp)
            {
                if (Environment.ExitCode > 0)
                    throw exp;
                return new byte[0];
            }
        }



        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="input">输入</param>
        /// <param name="password">密码</param>
        /// <param name="vector">加密向量</param>
        /// <param name="mode">密码模式</param>
        /// <returns></returns>
        protected virtual string doEncrypt(string input, string password, string vector, CipherMode mode)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                return string.Empty;
            }
            byte[] myInput = Encoding.UTF8.GetBytes(input);
            byte[] buffer = instance.doEncrypt(myInput, password, vector, mode);
            return Convert.ToBase64String(buffer);
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="input">输入</param>
        /// <param name="password">密码 长度是8的整数倍</param>
        /// <param name="vector">加密向量</param>
        /// <param name="mode">密码模式</param>
        /// <returns></returns>
        protected virtual byte[] doEncrypt(byte[] input, string password, string vector, CipherMode mode)
        {
            if (input == null || input.Length == 0)
            {
                return new byte[0];
            }
            if (string.IsNullOrWhiteSpace(password))
            {
                password = DEFAULT_PASSWORD;
            }
            if(string.IsNullOrWhiteSpace(vector))
            {
                vector = DEFAULT_VECTOR;
            }
            MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
            //必须转成散列字节数组，否则会抛出 指定键的大小对于此算法无效
            byte[] key = hashmd5.ComputeHash(Encoding.UTF8.GetBytes(password));
            try
            {
                var des = new TripleDESCryptoServiceProvider
                {
                    Key = key,
                    Mode = CipherMode.CBC,
                    Padding = PaddingMode.PKCS7
                };
                if (mode == CipherMode.CBC)
                {
                    //3des 仅支持8字节向量，其他任何长度都不支持！
                    //des 可以支持8字节、16字节
                    des.IV = hashmd5.ComputeHash(Encoding.UTF8.GetBytes(vector)).Take(8).ToArray();
                }
                var desEncrypt = des.CreateEncryptor();
                byte[] buffer = input;
                return desEncrypt.TransformFinalBlock(buffer, 0, buffer.Length);
            }
            catch (Exception exp)
            {
                if (Environment.ExitCode > 0)
                    throw exp;
                return new byte[0];
            }
        }
    }
}
